package com.sencorsta.ids.pay;

import com.alibaba.fastjson.JSON;
import com.sencorsta.utils.net.HttpRequester;
import com.sencorsta.utils.net.HttpRespons;

import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * 请求实现
 *
 * @author TFpay
 * @version 2.0
 */
public class HttpRequest {
    // request base URL
    private static final String BASE_URL = "https://0d49c00735f95913.com/";
    //跳转支付页接口
    private static final String GATE_WAY = "gateway";
    //查询接口
    private static final String QUERY = "query";

    /**
     * 正则表达式匹配 商户订单是否符合规则
     *
     * @param outTradeNo
     * @return
     */
    private static Boolean regular(String outTradeNo) {
        String REGULAR = "^[0-9a-zA-Z_]{1,}$";
        return outTradeNo.matches(REGULAR);
    }

    /**
     * 校验商户长度，以及商户规则
     *
     * @param outTradeNo 200成功  0 长度错误 1订单错误
     * @return
     */
    public static int verifyOutTradeNo(String outTradeNo) {
        // 判断商户号长度
        if (outTradeNo.length() < 64 && outTradeNo.length() > 0) {
            //正则匹配 商户订单
            if (regular(outTradeNo)) {
                return 200;
            } else {
                System.out.println("商户订单号:只能包含字母、数字、下划线");
                return 1;
            }
        } else {
            System.out.println("商户订单号长度不能超过64位 ");
            return 0;
        }
    }

    /**
     * 获取支付类型
     * @param payTypeNo 1 微信扫码“wechat_qr” 2支付宝扫码 “alipay_qr” 其他数字默认返回wechat_qr
     * @return 返回支付类型
     */
    public static String getPayType(int payTypeNo) {
        String payType = "wechat_qr";
        switch (payTypeNo) {
            case 1:
                payType = "wechat_qr";
                break;
            case 2:
                payType = "alipay_qr";
                break;
            default:
                payType = "wechat_qr";
                System.out.println("输入类型有误");
                break;
        }
        return payType;
    }

    /**
     * 生产Sign
     * 签名生成的通用步骤如下：
     * 第一步，设所有发送或者接收到的数据为集合M，将集合M内非空参数值的参数按照参数名ASCII码从小到大排序（字典序），使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串stringA。
     * 特别注意以下重要规则：
     * ◆ 参数名ASCII码从小到大排序（字典序）；
     * ◆ 如果参数的值为空不参与签名；
     * ◆ 参数名区分大小写；
     * ◆ 接口可能增加字段，验证签名时必须支持增加的扩展字段
     * 第二步，在stringA最后拼接上key得到stringSignTemp字符串，并对stringSignTemp进行MD5运算，得到sign值signValue。
     * ◆ key直接拼接，前面无须加&key=
     *
     * @param param
     * @return 返回sign
     */
    private static String getSign(Map<String, String> param, String key) {
        Map<String, String> valueParam = sortMapByKey(param);
        StringBuffer stringBuffer = new StringBuffer();
        for (Map.Entry<String, String> entry : valueParam.entrySet()) {
            stringBuffer.append(entry.getKey() + "=").append(entry.getValue() + "&");
        }
        String subSign = stringBuffer.toString();
        // key 可能会更换
        String sign = subSign.substring(0, subSign.length() - 1) + key;
        sign = getMD5Str(sign);
        return sign;
    }

    /**
     * 使用 Map按key进行排序
     *
     * @param map
     * @return
     */
    private static Map<String, String> sortMapByKey(Map<String, String> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        Map<String, String> sortMap = new TreeMap<String, String>(new MapKeyComparator());
        sortMap.putAll(map);
        return sortMap;
    }

    /**
     * 对字符串MD5
     *
     * @param str
     * @return
     * @throws Exception
     */
    private static String getMD5Str(String str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str.getBytes());
            // digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
            return new BigInteger(1, md.digest()).toString(16);
        } catch (Exception e) {
            System.out.println("MD5加密出现错误，" + e.toString());
        }
        return "";
    }

    /**
     * 跳转支付页接口
     *
     * @param mchId       商户ID:可在支付商户后台获取，如：100010
     * @param outTradeNo  商户订单号:64个字符以内、可包含字母、数字、下划线；需保证在商户端不重复
     * @param payType     支付渠道:推荐用文本框让商户自行更换如：微信扫码“wechat_qr” 支付宝扫码 “alipay_qr”
     * @param orderAmount 订单金额 ：如 “100.00”、“0.01”精确到2位小数
     * @param notifyUrl   回调：接收腾飞支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数。
     * @param userCode    会员标识：商户系统内部会员的唯一标识，可以是会员ID
     * @param key         可以配置的秘钥
     * @return 支付页接口返回值
     */
    public static String getGateWay(String mchId, String outTradeNo, String payType, Double orderAmount, String notifyUrl, String userCode, String key) {
        String tateWay = BASE_URL + GATE_WAY;
        Map<String, String> param = new HashMap<>();
        param.put("pay_type", payType);
        String money = new java.text.DecimalFormat("#.00").format(orderAmount);
        param.put("order_amount", money);
        param.put("notify_url", notifyUrl);
        param.put("user_code", userCode);
        param.put("mch_id", mchId);
        param.put("out_trade_no", outTradeNo);
        String sign = getSign(param, key);
        param.put("sign", sign);

        HttpRequester requester=new HttpRequester();
        HttpRespons respons= null;
        try {
            respons = requester.sendPost(tateWay, JSON.parseObject(JSON.toJSONString(param)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //String respons = HttpClientHelper.sendPost(tateWay, param);
        return respons.getContent();
    }

    /**
     * 查询接口
     *
     * @param mchId      商户ID:可在支付商户后台获取，如：100010
     * @param outTradeNo 商户订单号:64个字符以内、可包含字母、数字、下划线；需保证在商户端不重复
     * @param key        可以配置的秘钥
     * @return 查询接口返回值
     */
    public static String getQuery(String mchId, String outTradeNo, String key) {
        String query = BASE_URL + QUERY;
        Map<String, String> param = new HashMap<>();
        param.put("mch_id", mchId);
        param.put("out_order_no", outTradeNo);
        String sign = getSign(param, key);
        param.put("sign", sign);
        //String respons = HttpClientHelper.sendPost(query, param);
        HttpRequester requester=new HttpRequester();
        HttpRespons respons= null;
        try {
            respons = requester.sendPost(query, JSON.parseObject(JSON.toJSONString(param)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //String respons = HttpClientHelper.sendPost(tateWay, param);
        return respons.getContent();
    }

    /**
     * @param myUrl       地址由getMyGateWay()方法中的pay_url生成
     * @param mchId       商户ID:可在支付商户后台获取，如：100010
     * @param outTradeNo  商户订单号:64个字符以内、可包含字母、数字、下划线；需保证在商户端不重复
     * @param orderAmount 订单金额 ：如 “100.00”、“0.01”精确到2位小数
     * @param payAmount   实付金额
     * @param key         可以配置的秘钥
     * @return 回调返回值
     */
    public static String getCallBackUrl(String myUrl, String mchId, String outTradeNo, Double orderAmount, Double payAmount, String key) {
        Map<String, String> param = new HashMap<>();
        param.put("mch_id", mchId);
        param.put("out_order_no", outTradeNo);
        param.put("order_state", "1");
        String money = new java.text.DecimalFormat("#.00").format(orderAmount);
        param.put("order_amount", money);
        String payMoney = new java.text.DecimalFormat("#.00").format(payAmount);
        param.put("pay_amount", payMoney);
        String sign = getSign(param, key);
        param.put("sign", sign);
        //String respons = HttpClientHelper.sendPost(myUrl, param);
        HttpRequester requester=new HttpRequester();
        HttpRespons respons= null;
        try {
            respons = requester.sendPost(myUrl, JSON.parseObject(JSON.toJSONString(param)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //String respons = HttpClientHelper.sendPost(tateWay, param);
        return respons.getContent();
    }
}
